package com.displayCongress;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class CongressSocket extends Socket implements Runnable
{
	private final int BLOCK_SIZE = 1024;
	
	private ArrayList<Byte> readResult = new ArrayList<Byte>();
	
	private DataInputStream inDataStream;
	private DataOutputStream outDataStream;
	
	private boolean loggedIn = false;
	
	public CongressSocket(String remoteMachine, int port) throws IOException
	{
		super(remoteMachine, port);
		
		InputStream inStream = getInputStream();
		inDataStream = new DataInputStream(inStream);
		
		OutputStream outStream = getOutputStream();
		outDataStream = new DataOutputStream(outStream);
		
		new Thread(this).start();
	}
	
	private String getExtension(File f)
	{
		int dot = f.getAbsolutePath().lastIndexOf(".");
	    return f.getAbsolutePath().substring(dot + 1);
	}
	
	public boolean send(File f) throws IOException
	{
		String ext = getExtension(f);

		boolean result = true;
		
		result &= send("<name>" + f.getName() + "</name><type>file</type><data>");
		
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		if (ext.equals("png") || ext.equals("jpg") || ext.equals("gif"))
		{
			Bitmap bm = BitmapFactory.decodeFile(f.getAbsolutePath());
			bm.compress(Bitmap.CompressFormat.valueOf(ext), 100, bos);
		}
		else
		{
			FileInputStream fis = new FileInputStream(f);
			InputStream bis = new BufferedInputStream(fis);
			
			byte[] b = new byte[BLOCK_SIZE];
			int bytesRead;
			while ((bytesRead = bis.read(b)) != -1 && result) 
			{
				bos.write(b, 0, bytesRead);
			}
		}
		
		result &= send(bos.toByteArray());
		
		result &= send("</data><EOF>");
		
		return result;
	}
	
	public boolean sendURL(String url)
	{
		boolean result = true;
		
		Pattern pattern = Pattern.compile("(http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?");
		Matcher matcher = pattern.matcher(url);
		if (!matcher.matches())
		{
			return false;
		}
		
		result &= send("<name></name><type>url</type><data>");
		result &= send(url.trim().getBytes());
		result &= send("</data>");
		result &= sendEOF();
		
		return result;
	}
	
	private boolean send(byte[] bytes)
	{		
		String result = "";
		
		int[] encoded = encode(bytes);
//		byte[] encoded = bytes;
		
		for (int i = 0; i < bytes.length; i++)
		{
            String hex = toHex(encoded[i]);
            if (!hex.equals("0"))
            {
                result += hex;
            }
		}
		
		return send(result);
	}
	
	private boolean send(String bytes)
	{
		try 
		{
			outDataStream.writeBytes(bytes);
		} 
		catch (IOException e) 
		{
			return false;
		}
		
		return true;
	}
	
	private boolean send(int i)
	{
		try
		{
			outDataStream.writeInt(i);
		} 
		catch (IOException e) 
		{
			return false;
		}
		
		return true;
	}
	
	public boolean sendEOF()
	{
		try 
		{
			outDataStream.writeBytes("<EOF>");
		} 
		catch (IOException e) 
		{
			return false;
		}
		
		return true;
	}
	
	public boolean login(String username, String password)
	{
		boolean result = true;
		
		result &= send("<name>");
		result &= send(username.getBytes());
		result &= send("</name><type>login</type><data>");
		result &= send(password.getBytes());
		result &= send("</data>");
		result &= sendEOF();
		
		return result;
	}
	
	public synchronized byte[] read()
	{		
		byte[] temp = new byte[BLOCK_SIZE];
		
		try
		{
			boolean runWhile = true;
			while(runWhile && inDataStream.read(temp) != -1)
			{
				for (int i = 0; i < temp.length; i++)
				{
					byte t = temp[i];
					if (t != 0)
					{
						readResult.add(t);
					}
					else
					{
						runWhile = false;
						break;
					}
					
				}
			}
		}
		catch (IOException e) {}
		
		byte[] bytes = new byte[readResult.size()];
		
		for (int i = 0; i < readResult.size(); i++)
		{
			bytes[i] = readResult.get(i);
		}
		
		return bytes;
	}
	
	private int[] encode(byte[] bytes)
	{
		int[] result = new int[bytes.length];
		
		for (int i = 0; i < bytes.length; i++)
		{
			int bits = 0;
		    for (int j = 0; j < 8; j++)
		    {  
		        bits += (int) (!((bytes[i] & (byte) Math.pow(2, j)) > 0) ? Math.pow(2, j) : 0);
		    }  
	    
		    result[i] = bits;
			
		}
		
		return result;
	}
	
	// Make sure every byte is represented by 2 hexadecimal values
	private String toHex(int v)
	{
		return v > 15 ? Integer.toHexString(v) : "0" + Integer.toHexString(v);
	}
	
	public boolean isLoggedIn()
	{
		return loggedIn;
	}

	public void run() 
	{
		while (this.isConnected())
		{
			byte[] read = read();
			if (read.length > 0)
			{
				System.out.println(new String(read));
				
				if ((new String(read)).contains("_loggedin_"))
				{
					loggedIn = true;
				}
			}
			
			try 
			{
				Thread.sleep(250);
			} 
			catch (InterruptedException e) {}
		}
		
		loggedIn = false;
		
		try 
		{
			inDataStream.close();
			outDataStream.close();
		} 
		catch (IOException e) {}
	}
}